package com.yss.reportworld.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yss.common.core.constant.SecurityConstants;
import com.yss.common.core.domain.YssResponse;
import com.yss.common.core.enums.YssConfigEnum;
import com.yss.common.core.enums.YssStatusEnum;
import com.yss.common.core.exception.BusinessException;
import com.yss.common.core.utils.StringUtils;
import com.yss.common.security.utils.DictUtils;
import com.yss.reportworld.domain.*;
import com.yss.reportworld.enums.ReportWorldEnum;
import com.yss.reportworld.enums.ReportWorldStandardCheckTableCodeEnum;
import com.yss.reportworld.mapper.TableDetailMapper;
import com.yss.reportworld.service.*;
import com.yss.system.api.RemoteConfigService;
import lombok.extern.slf4j.Slf4j;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yss.reportworld.mapper.TableStandardCheckMapper;
import org.springframework.util.CollectionUtils;

/**
 * 校验规则Service业务层处理
 *
 * @author yss
 * @date 2023-03-30
 */
@Slf4j
@Service
public class TableStandardCheckServiceImpl extends ServiceImpl<TableStandardCheckMapper, TableStandardCheck> implements ITableStandardCheckService {
    /* @Autowired
     private ITableDetailService tableDetailService;*/
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private IReportService reportService;
    @Autowired
    private IModularService modularService;
    @Autowired
    private RemoteConfigService remoteConfigService;
    // MYSQl最大长度限制
    private final int VARCHAR_MAX_ROW_SIZE = 65535;
    @Autowired
    private TableDetailMapper tableDetailMapper; // 按照版本校验

    /**
     * 查询校验规则列表
     *
     * @param tableStandardCheck 校验规则
     * @return 校验规则
     */
    @Override
    public List<TableStandardCheck> selectTableStandardCheckList(TableStandardCheck tableStandardCheck) {
        QueryWrapper<TableStandardCheck> wrapper = new QueryWrapper();
        wrapper.orderByDesc("STATUS");
        if (null == tableStandardCheck) {
            return this.list(wrapper);
        }
        if (StringUtils.isNotEmpty(tableStandardCheck.getCheckCode())) {
            wrapper.eq("CHECK_CODE", tableStandardCheck.getCheckCode());
        }
        if (StringUtils.isNotEmpty(tableStandardCheck.getTableNamePrefix())) {
            wrapper.eq("TABLE_NAME_PREFIX", tableStandardCheck.getTableNamePrefix());
        }
        if (StringUtils.isNotEmpty(tableStandardCheck.getTableNameSuffix())) {
            wrapper.eq("TABLE_NAME_SUFFIX", tableStandardCheck.getTableNameSuffix());
        }
        if (StringUtils.isNotEmpty(tableStandardCheck.getTableNameContain())) {
            wrapper.eq("TABLE_NAME_CONTAIN", tableStandardCheck.getTableNameContain());
        }
        if (null != tableStandardCheck.getStatus()) {
            wrapper.eq("STATUS", tableStandardCheck.getStatus());
        }
        // 导出的时候选择了数据，按照选择的数据
        if (StringUtils.isNotEmpty(tableStandardCheck.getIds())) {
            List<String> list = JSONArray.parseArray(tableStandardCheck.getIds(), String.class);
            if (StringUtils.isNotEmpty(list)) {
                wrapper.in("ID", list);
            }
        }
        Map<String, Customer> mapCustomer = customerService.getCustomerMap();
        Map<String, Report> mapReport = reportService.getReportMap();
        Map<String, Modular> mapModular = modularService.getModularMap();
        Map<String, String> mapTableLayered = DictUtils.getDictCacheMap(ReportWorldEnum.REPORT_TABLE_LAYERED.getCode());
        List<TableStandardCheck> list = this.list(wrapper);
        if (StringUtils.isEmpty(list)) {
            return list;
        }
        for (TableStandardCheck standardCheck : list) {
            ReportWorldStandardCheckTableCodeEnum baseEnum = ReportWorldStandardCheckTableCodeEnum.getEnum(standardCheck.getCheckCode());
            if (StringUtils.isNull(baseEnum)) {
                continue;
            }
            // 加载对应的值
            switch (baseEnum) {
                case LAYERED:
                    //报表世界所在分层
                    if (StringUtils.isNotEmpty(mapTableLayered) && mapTableLayered.containsKey(standardCheck.getCheckValue())) {
                        standardCheck.setCheckValue(mapTableLayered.get(standardCheck.getCheckValue()));
                    }
                    break;
                case CUSTOMER:
                    if (StringUtils.isNotEmpty(mapCustomer) && mapCustomer.containsKey(standardCheck.getCheckValue())
                            && null != mapCustomer.get(standardCheck.getCheckValue())) {
                        standardCheck.setCheckValue(mapCustomer.get(standardCheck.getCheckValue()).getName());
                    }
                    break;
                case REPORT:
                    if (StringUtils.isNotEmpty(mapReport) && mapReport.containsKey(standardCheck.getCheckValue())
                            && null != mapReport.get(standardCheck.getCheckValue())) {
                        standardCheck.setCheckValue(mapReport.get(standardCheck.getCheckValue()).getName());
                    }
                    break;
                case MODULAR:
                    if (StringUtils.isNotEmpty(mapModular) && mapModular.containsKey(standardCheck.getCheckValue())
                            && null != mapModular.get(standardCheck.getCheckValue())) {
                        standardCheck.setCheckValue(mapModular.get(standardCheck.getCheckValue()).getName());
                    }
                    break;
                default:
                    throw new BusinessException("系统没有获取到对应的校验规则");
            }
        }
        return list;
    }

    /**
     * 校验规则是否唯一
     *
     * @param tableStandardCheck
     * @return 结果
     */
    @Override
    public boolean checkTableStandardUnique(TableStandardCheck tableStandardCheck) {
        String tableStandardCheckId = StringUtils.isNull(tableStandardCheck.getId()) ? "-1" : tableStandardCheck.getId();
        QueryWrapper<TableStandardCheck> wrapper = new QueryWrapper<>();
        wrapper.eq("CHECK_CODE", tableStandardCheck.getCheckCode());
        wrapper.eq("CHECK_VALUE", tableStandardCheck.getCheckValue());
        TableStandardCheck info = this.getOne(wrapper);
        if (StringUtils.isNotNull(info) && !info.getId().equals(tableStandardCheckId)) {
            return false;
        }
        return true;
    }


    /**
     * 新增时候检验规范
     *
     * @return
     * @throws Exception
     */
    public void tableStandardCheckInfo(List<Table> list, boolean isDetail) {
        if (CollectionUtils.isEmpty(list)) {
            log.error("没有获取到要校验的表信息");
            throw new BusinessException("没有获取到要校验的表信息");
        }
        Map<Object, List<TableStandardCheck>> map = this.getTableStandardCheckMap();
        if (CollectionUtils.isEmpty(map)) {
            log.error("没有获取到要校验的表信息");
            return;
        }
        for (Table table : list) {
            if (null == table || StringUtils.isNotEmpty(table.getName())) {
                continue;
            }
            if (StringUtils.isNotEmpty(table.getChineseName())) {
                throw new BusinessException(table.getName() + "表没有获取到中文名称，请检查！");
            }
            List<String> listEnum = ReportWorldStandardCheckTableCodeEnum.getReportWorldStandardCheckTableEnum();
            for (String code : listEnum) {
                List<TableStandardCheck> checkList = map.get(code);
                if (CollectionUtils.isEmpty(checkList)) {
                    continue;
                }
                this.checktableStandard(table, code, checkList);
            }
            if (isDetail) {
                this.checkTableDetail(table);
            }
        }
    }

    /**
     * 表的校验
     *
     * @param table
     * @throws Exception
     */
    public void tableStandardCheckInfo(Table table, boolean isDetail) {
        if (null == table || StringUtils.isBlank(table.getName())) {
            log.error("没有获取到要校验的表信息");
            throw new BusinessException("没有获取到要校验的表信息");
        }
        if (StringUtils.isBlank(table.getChineseName())) {
            throw new BusinessException(table.getName() + "表没有获取到中文名称，请检查！");
        }
        Map<Object, List<TableStandardCheck>> map = this.getTableStandardCheckMap();
        if (CollectionUtils.isEmpty(map)) {
            log.error("没有获取到要校验的表信息");
            return;
        }
        List<String> listEnum = ReportWorldStandardCheckTableCodeEnum.getReportWorldStandardCheckTableEnum();
        for (String code : listEnum) {
            List<TableStandardCheck> checkList = map.get(code);
            if (CollectionUtils.isEmpty(checkList)) {
                continue;
            }
            this.checktableStandard(table, code, checkList);
        }
        if (isDetail) {
            this.checkTableDetail(table);
        }
    }

    /**
     * 检查表时候有字段
     *
     * @param table
     * @throws Exception
     */
    private void checkTableDetail(Table table) {
        if (null == table || StringUtils.isBlank(table.getName())) {
            throw new BusinessException("没有获取到表名称信息，请检查！");
        }
        QueryWrapper<TableDetail> detailQueryWrapper = new QueryWrapper<>();
        detailQueryWrapper.in("TABLE_ID", table.getId());
        detailQueryWrapper.eq("STATUS", YssStatusEnum.NORMAL.getCode());
        List<TableDetail> listDetail = tableDetailMapper.selectList(detailQueryWrapper);
        if (CollectionUtils.isEmpty(listDetail)) {
            throw new BusinessException(table.getName() + "表结构里没有状态是正常的字段信息，请检查！");
        }
        this.calcColumnLength(listDetail, table);
    }

    /**
     * 检查字段总长度，MYSQL的会有限制
     *
     * @param listDetail
     */
    private void calcColumnLength(List<TableDetail> listDetail, Table table) {
        YssResponse<String> response = remoteConfigService.getConfigByKey(YssConfigEnum.REPORTWORLD_MYSQL_TABLE_CHECK.getCode(), SecurityConstants.INNER);
        if (!"true".equals(response.getData())) {
            return;
        }
        // mysql的是否表字段总数不能超过长度
        if (listDetail.size() > 100) {
            throw new BusinessException("表【" + table.getName() + "】【" + table.getChineseName() + "】" + "不合理的表结构设计，列太多！！！");
        }
        int num = 0;
        for (TableDetail tableDetail : listDetail) {
            if (StringUtils.isNull(tableDetail) || null == tableDetail.getColumnType() || null == tableDetail.getColumnLength()) {
                continue;
            }
            Integer columnType = tableDetail.getColumnType();
            switch (columnType) {
                case 1:
                    num += tableDetail.getColumnLength() * 3 + 2;
                    break;
                case 2:
                    num += 8;
                    break;
                case 3:
                    num += 8;
                    break;
                case 4:
                    num += 8;
                    break;
                case 5:
                    num += 4;
                    break;
                case 6:
                    num += 8;
                    break;
                case 7:
                    num += 8;
                    break;
                case 8:
                    num += 8;
                    break;
                case 9:
                    num += tableDetail.getColumnLength() * 3 + 2;
                    break;
                case 10:
                    num += tableDetail.getColumnLength() * 3;
                    break;
                case 11:
                    num += 4;
                    break;
                case 12:
                    num += 4;
                    break;
                default:
                    break;
            }
        }
        if (num > VARCHAR_MAX_ROW_SIZE) {
            throw new BusinessException("表【" + table.getName() + "】【" + table.getChineseName() + "】" + "不合理的表结构设计，列长度会超过了MYSQL的限制！！！");
        }
    }

    /**
     * 按照检查CODE 存放数据MAP
     *
     * @throws Exception
     */
    private Map<Object, List<TableStandardCheck>> getTableStandardCheckMap() {
        QueryWrapper<TableStandardCheck> wrapper = new QueryWrapper();
        wrapper.eq("STATUS", YssStatusEnum.NORMAL.getCode());
        List<TableStandardCheck> checkList = this.list(wrapper);
        if (StringUtils.isEmpty(checkList)) {
            log.info("没有获取到表的校验规则信息!");
            return null;
        }
        Map<Object, List<TableStandardCheck>> map = new HashMap<>();
        for (TableStandardCheck check : checkList) {
            if (null == check || StringUtils.isEmpty(check.getCheckCode())) {
                continue;
            }
            if (map.containsKey(check.getCheckCode())) {
                List<TableStandardCheck> list = map.get(check.getCheckCode());
                if (!CollectionUtils.isEmpty(list)) {
                    list.add(check);
                    map.put(check.getCheckCode(), list);
                }
            } else {
                List<TableStandardCheck> list = new ArrayList<>();
                list.add(check);
                map.put(check.getCheckCode(), list);
            }
        }
        return map;
    }

    /**
     * 按照类型获取对用的表规则集合
     *
     * @return
     * @throws Exception
     */
    private void checktableStandard(Table table, String code, List<TableStandardCheck> checkList) {
        ReportWorldStandardCheckTableCodeEnum baseEnum = ReportWorldStandardCheckTableCodeEnum.getEnum(code);
        switch (baseEnum) {
            case LAYERED:
                if (null == table.getLayered()) {
                    break;
                }
                this.checktableStandardInfo(String.valueOf(table.getLayered()), checkList, code, table);
                break;
      /*      case FTYPE:
                if (null == table.getFtype()) {
                    break;
                }
                this.checktableStandardInfo(String.valueOf(table.getFtype()), checkList, code, table);
                break;
            case FSOURCE:
                if (null == table.getFsource()) {
                    break;
                }
                this.checktableStandardInfo(String.valueOf(table.getFsource()), checkList, code, table);
                break;*/
            case CUSTOMER:
                if (StringUtils.isNotEmpty(table.getStrCustomer())) {
                    for (String customerId : table.getStrCustomer()) {
                        this.checktableStandardInfo(customerId, checkList, code, table);
                    }
                    break;
                }
                break;
            case REPORT:
                if (StringUtils.isNotEmpty(table.getStrReport())) {
                    for (String reportId : table.getStrReport()) {
                        this.checktableStandardInfo(reportId, checkList, code, table);
                    }
                    break;
                }
                break;
            case MODULAR:
                if (StringUtils.isNotEmpty(table.getStrModular())) {
                    for (String modularId : table.getStrModular()) {
                        this.checktableStandardInfo(modularId, checkList, code, table);
                    }
                    break;
                }
                break;
            default:
                throw new BusinessException("系统没有获取到对应的校验规则");
        }
    }

    /**
     * 表信息校验
     */
    private void checktableStandardInfo(String value, List<TableStandardCheck> checkList, String code, Table
            table) {
        if (CollectionUtils.isEmpty(checkList) || StringUtils.isBlank(value)) {
            return;
        }
        StringBuffer msg = new StringBuffer();
        for (TableStandardCheck check : checkList) {
            if (null == check) {
                continue;
            }
            if (!value.equals(check.getCheckValue())) {
                continue;
            }
            String enumDesc = ReportWorldStandardCheckTableCodeEnum.getEnumDesc(code);
            // 前缀校验
            if (StringUtils.isNotBlank(check.getTableNamePrefix()) && !table.getName().toUpperCase().startsWith(check.getTableNamePrefix())) {
                // throw new BusinessException(enumDesc + "，表前缀不规范，规则中表的前缀必须是" + check.getTableNamePrefix());
                msg.append(enumDesc + "，表前缀不规范，规则中表的前缀必须是" + check.getTableNamePrefix()).append("\r\n");
            }
            if (StringUtils.isNotBlank(check.getTableNameSuffix()) && !table.getName().toUpperCase().endsWith(check.getTableNameSuffix())) {
                // throw new BusinessException(enumDesc + "，表后缀不规范，规则中表的后缀必须是" + check.getTableNamePrefix());
                msg.append(enumDesc + "，表后缀不规范，规则中表的后缀必须是" + check.getTableNamePrefix()).append("\r\n");
            }
            if (StringUtils.isNotBlank(check.getTableNameContain()) && table.getName().toUpperCase().indexOf(check.getTableNameContain()) <= -1) {
                // throw new BusinessException(enumDesc + "，表名不规范，规则中表的名字必须包含" + check.getTableNameContain());
                msg.append(enumDesc + "，表名不规范，规则中表的名字必须包含" + check.getTableNameContain()).append("\r\n");
            }
        }
        if (StringUtils.isNotEmpty(msg)) {
            throw new BusinessException(msg.toString());
        }

    }

}
